﻿// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2023 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

using Abc.Application;
using Furion.Logging;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IO;

namespace Abc.Web.Core
{
    [AppStartup(700)]
    public class Startup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddConfigurableOptions<AppInfoOptions>();//选项不同于配置，需在应用启动时注册
            services.AddConfigurableOptions<DbSettingOptions>();
            services.AddAbcMvcInit();//ABC内置的

            services.AddFileLogging(options =>
            {
                //options.MessageFormat = LoggerFormatter.JsonIndented;
                //启用备用日志文件功能，也就是如果文件被占用了，可以创建新的备用日志继续写入，推荐！！！
                options.HandleWriteError = (writeError) =>
                {
                    writeError.UseRollbackFileName(Path.GetFileNameWithoutExtension(writeError.CurrentFileName) + "-oops" + Path.GetExtension(writeError.CurrentFileName));
                };
            });

            #region 分布式缓存 SqlServer,其它方式后面在加

            //注册分布式数据库缓存
            //services.AddDistributedSqlServerCache(options =>
            //{
            //    options.ConnectionString = Configuration.GetConnectionString("DbCacheConnectionString");
            //    options.SchemaName = "dbo";
            //    options.TableName = "sys_DataCache";
            //    options.SystemClock = new SystemClockEx();
            //});

            #endregion 分布式缓存 SqlServer,其它方式后面在加

            #region ActionFilter 授权验证

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
           //后台
           .AddCookie(AuthorizeType.AdminAuthenticationScheme, options =>
           {
               //options.AccessDeniedPath = "/Account/Forbidden";
               options.LoginPath = "/HtAdmin/Login/Index";
               options.LogoutPath = "/HtAdmin/Login/LoginOut";
           });

            #endregion ActionFilter 授权验证

            // 默认授权机制，需授权的即可（方法）需贴 `[Authorize]` 特性
            //services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);//必须在 .AddControllers() 之前注册！！

            services.AddCorsAccessor();//添加跨域配置
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromDays(1);// TimeSpan.FromMinutes(30);
            }); //Session

            services.Configure<RazorViewEngineOptions>(options =>
            {
                //自定视图文件，添加视图子文件夹的情况下很有用
                // 区域
                // 添加自定义视图路径方法
                // Areas/HtAdmin/Views/ERL/Article/Index.cshtml
                // Areas/区域名称/Views/文件夹名称/控制器Controller/方法Action.cshtml
                // Areas/{2}/Views/ERL/{1}/{0}.cshtml

                var types = new List<string>() {
                    "Defaults",//默认
                    "Devs",//开发的
                    "Syss",//系统设置
                    "Manager",//管理
                    "Email",//邮件
                    };
                foreach (var type in types)
                {
                    options.AreaViewLocationFormats.Add($"~/Areas/{{2}}/Views/{type}/{{1}}/{{0}}" + RazorViewEngine.ViewExtension);
                }

                //options.AreaViewLocationFormats.Add("~/Areas/{2}/Views/Defaults/{1}/{0}" + RazorViewEngine.ViewExtension);
                //options.AreaViewLocationFormats.Add("~/Areas/{2}/Views/Devs/{1}/{0}" + RazorViewEngine.ViewExtension);
                //options.AreaViewLocationFormats.Add("~/Areas/{2}/Views/Syss/{1}/{0}" + RazorViewEngine.ViewExtension);
                //options.AreaViewLocationFormats.Add("~/Areas/{2}/Views/Manager/{1}/{0}" + RazorViewEngine.ViewExtension);
                // 非区域 添加自定义视图路径方法 /Views/ERL/Article/Index.cshtml
                // /Views/文件夹名称/控制器Controller/方法Action.cshtml /Views/ERL/{1}/{0}.cshtml options.ViewLocationFormats.Add("~/Views/ERL/{0}"+RazorViewEngine.ViewExtension);
            });

            services.AddRazorPages();
            services.AddControllersWithViews(options =>
            {
                //Web 拦截器
                //options.Filters.Add(new GlobalLogFilter());
                ////此处注册全局 输入验证
                //options.Filters.Add(new ValidateEntityFilterAttribute(ValidationEntityType.All, isMvcReutrnMultipleErrors: true));
                //此处 注册全局   防止重复提交 特性(影响性能,有1~10毫秒左右影响)
                options.Filters.Add(new PreventSpamFilterAttribute(httpAccessInterval: 1000));
                options.Filters.Add(new XSSFilterAttribute());//xss攻击防御
            })
                .AddAbcJsonOptions(isLongToString: true)//system.text.json
                                                        //.AddAbcNewtonsoftJson()//newtonsoft.json 这两个使用一个就好了

                .AddAppLocalization() // 注册多语言
                .AddInjectWithUnifyResult(options => { });

            //对于获取客户端 IP 的场景只需要指定 ForwardedHeaders.XForwardedFor
            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                //清除已知网络和已知代理的默认列表
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });
            // 添加实时通讯
            services.AddSignalR();

            //滑块验证码
            services.AddDistributedMemoryCache();
            services.AddSlideCaptcha(App.Configuration);


            //图形验证码
            services.AddCaptcha(App.Configuration);

            //, option =>
            //  {
            //      option.CaptchaType = CaptchaType.WORD; // 验证码类型
            //      option.CodeLength = 4; // 验证码长度, 要放在CaptchaType设置后.  当类型为算术表达式时，长度代表操作的个数
            //      option.ExpirySeconds = 30; // 验证码过期时间
            //      option.IgnoreCase = true; // 比较时是否忽略大小写
            //      option.StoreageKeyPrefix = ""; // 存储键前缀

            //      option.ImageOption.Animation = true; // 是否启用动画
            //      option.ImageOption.FrameDelay = 30; // 每帧延迟,Animation=true时有效, 默认30

            //      option.ImageOption.Width = 150; // 验证码宽度
            //      option.ImageOption.Height = 50; // 验证码高度
            //      option.ImageOption.BackgroundColor = SkiaSharp.SKColor.Parse("#fff"); // 验证码背景色

            //      option.ImageOption.BubbleCount = 2; // 气泡数量
            //      option.ImageOption.BubbleMinRadius = 5; // 气泡最小半径
            //      option.ImageOption.BubbleMaxRadius = 15; // 气泡最大半径
            //      option.ImageOption.BubbleThickness = 1; // 气泡边沿厚度

            //      option.ImageOption.InterferenceLineCount = 2; // 干扰线数量

            //      option.ImageOption.FontSize = 36; // 字体大小
            //      option.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; // 字体

            //      /* 
            //       * 中文使用kaiti，其他字符可根据喜好设置（可能部分转字符会出现绘制不出的情况）。
            //       * 当验证码类型为“ARITHMETIC”时，不要使用“Ransom”字体。（运算符和等号绘制不出来）
            //       */

            //      option.ImageOption.TextBold = true;// 粗体，该配置2.0.3新增
            //  }


            //防止跨站点请请求伪造xsrf/csrf
            services.AddCSRF();

            #region 远程服务

            services.AddRemoteRequest();//注册远程请求服务

            #endregion 远程服务

            services.AddViewEngine();//注册视图引擎
            //注册 监听日志
            //services.AddMvcFilter<LoggingMonitorAttribute>();
            services.AddMonitorLogging();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //如果环境是Development serve Developer Exception Page
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //否则显示用户友好的错误页面
            else if (env.IsStaging() || env.IsProduction() || env.IsEnvironment("UAT"))
            {
                app.UseExceptionHandler("/Error");
                app.UseStatusCodePagesWithReExecute("/Error/{0}");
            }

            if (env.IsDevelopment())
            {
                //添加 Forwarded Headers 中间件
                app.UseForwardedHeaders();
            }
            else
            {
                //添加 Forwarded Headers 中间件
                app.UseForwardedHeaders();
                app.UseHsts();
            }

            // 添加规范化结果状态码，需要在这里注册
            app.UseUnifyResultStatusCodes();
            // 配置多语言，必须在 路由注册之前
            app.UseAppLocalization();

            app.UseHttpsRedirection();
            app.UseCustomStaticFile();
            app.UseStaticFiles();

            //app.UseSerilogRequestLogging();    // 必须在 UseStaticFiles 和 UseRouting 之间
            app.UseRouting();
            app.UseCorsAccessor();
            app.UseSession();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseInject();

            //原生的Context中并没有包含客户端的IP地址跟端口号。
            //我们需要手动的在Nuget中引入
            //"Microsoft.AspNetCore.HttpOverrides": "1.0.0" 这个包
            app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });

            app.UseEndpoints(endpoints =>
            {
                // 批量注册集线器
                endpoints.MapHubs();
                endpoints.MapRazorPages();

                endpoints.MapAreaControllerRoute(
                    name: "areas", "areas",
                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

                endpoints.MapControllerRoute(
                    name: "areas",
                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
                );
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

            ApplicationInit.Init();

            Log.Information("测试测试");
        }
    }
}